package lapsnake.py.ast;


import java.beans.PropertyVetoException;

import org.python.antlr.*; 
import org.python.antlr.ast.*;
import org.python.antlr.base.*;

import lapsnake.model.*;
import lapsnake.model.slice.*;
import lapsnake.model.stmt.*;
import lapsnake.model.data.ChildField;
import lapsnake.model.data.ChildList;
import lapsnake.model.expr.*;
import lapsnake.model.misc.*;

/**Factory to generate helper classes for antlr PythonTree nodes.*/
public class ASTHelperFactory
{
	
	public static<X extends LapNode> X makeHelper(PyAST pyAST, ChildField<X> parentField, PythonTree node) throws NullPointerException, RuntimeException
	{
		try
		{
			X r = parentField.cast(makeHelperOrNull(pyAST, parentField, node));
			if(r == null)
			{
				if(parentField.isList())
					throw new NullPointerException("Cannot add null element to child list: "+parentField);
				else if(!parentField.isOptional())
					throw new NullPointerException("Cannot generate AST helper for null: "+parentField+" is not optional");
			}
			return r;
		}
		catch (PropertyVetoException e)
		{
			throw new RuntimeException("Properties should not be vetoed during initialization...", e);
		}
	}
	@SuppressWarnings("unchecked")
	protected static LapNode makeHelperOrNull(PyAST pyAST, ChildField<?> parent, PythonTree node) throws RuntimeException, PropertyVetoException
	{
		if(node == null)
			return null;
		if(node instanceof mod) //mod
			return new LapModule(pyAST, (mod) node);
		if(node instanceof FunctionDef) // stmt
			return new LapFunctionDef(pyAST, (ChildField<? super LapFunctionDef>) parent, (FunctionDef) node);
		if(node instanceof ClassDef) // stmt
			return new LapClassDef(pyAST, (ChildField<? super LapClassDef>) parent, (ClassDef) node);
		if(node instanceof Return) // stmt
			return new LapReturn(pyAST, (ChildField<? super LapReturn>) parent, (Return) node);
		if(node instanceof Delete) // stmt
			return new LapDelete(pyAST, (ChildField<? super LapDelete>) parent, (Delete) node);
		if(node instanceof Assign) // stmt
			return new LapAssign(pyAST, (ChildField<? super LapAssign>) parent, (Assign) node);
		if(node instanceof AugAssign) // stmt
			return new LapAugAssign(pyAST, (ChildField<? super LapAugAssign>) parent, (AugAssign) node);
		if(node instanceof Print) // stmt
			return new LapPrint(pyAST, (ChildField<? super LapPrint>) parent, (Print) node);
		if(node instanceof For) // stmt
			return new LapFor(pyAST, (ChildField<? super LapFor>) parent, (For) node);
		if(node instanceof While) // stmt
			return new LapWhile(pyAST, (ChildField<? super LapWhile>) parent, (While) node);
		if(node instanceof If) // stmt
			return new LapIf(pyAST, (ChildField<? super LapIf>) parent, (If) node);
		if(node instanceof With) // stmt
			return new LapWith(pyAST, (ChildField<? super LapWith>) parent, (With) node);
		if(node instanceof Raise) // stmt
			return new LapRaise(pyAST, (ChildField<? super LapRaise>) parent, (Raise) node);
		if(node instanceof TryExcept) // stmt
			return new LapTryExcept(pyAST, (ChildField<? super LapTryExcept>) parent, (TryExcept) node);
		if(node instanceof TryFinally) // stmt
			return new LapTryFinally(pyAST, (ChildField<? super LapTryFinally>) parent, (TryFinally) node);
		if(node instanceof Assert) // stmt
			return new LapAssert(pyAST, (ChildField<? super LapAssert>) parent, (Assert) node);
		if(node instanceof Import) // stmt
			return new LapImport(pyAST, (ChildField<? super LapImport>) parent, (Import) node);
		if(node instanceof ImportFrom) // stmt
			return new LapImportFrom(pyAST, (ChildField<? super LapImportFrom>) parent, (ImportFrom) node);
		if(node instanceof Exec) // stmt
			return new LapExec(pyAST, (ChildField<? super LapExec>) parent, (Exec) node);
		if(node instanceof Global) // stmt
			return new LapGlobal(pyAST, (ChildField<? super LapGlobal>) parent, (Global) node);
		if(node instanceof Expr) // stmt
			return ExprEliminator.elimnateExpr(pyAST, (ChildField<? super LapStatement>) parent, (Expr) node);
		if(node instanceof Pass) // stmt
			return new LapPass(pyAST, (ChildField<? super LapPass>) parent, (Pass) node);
		if(node instanceof Break) // stmt
			return new LapBreak(pyAST, (ChildField<? super LapBreak>) parent, (Break) node);
		if(node instanceof Continue) // stmt
			return new LapContinue(pyAST, (ChildField<? super LapContinue>) parent, (Continue) node);
		if(node instanceof BoolOp) // expr
			return new LapBoolOp(pyAST, (ChildField<? super LapBoolOp>) parent, (BoolOp) node);
		if(node instanceof BinOp) // expr
			return new LapBinOp(pyAST, (ChildField<? super LapBinOp>) parent, (BinOp) node);
		if(node instanceof UnaryOp) // expr
			return new LapUnaryOp(pyAST, (ChildField<? super LapUnaryOp>) parent, (UnaryOp) node);
		if(node instanceof Lambda) // expr
			return new LapLambda(pyAST, (ChildField<? super LapLambda>) parent, (Lambda) node);
		if(node instanceof IfExp) // expr
			return new LapIfExp(pyAST, (ChildField<? super LapIfExp>) parent, (IfExp) node);
		if(node instanceof Dict) // expr
			return new LapDict(pyAST, (ChildField<? super LapDict>) parent, (Dict) node);
		if(node instanceof ListComp) // expr
			return new LapListComp(pyAST, (ChildField<? super LapListComp>) parent, (ListComp) node);
		if(node instanceof GeneratorExp) // expr
			return new LapGeneratorExp(pyAST, (ChildField<? super LapGeneratorExp>) parent, (GeneratorExp) node);
		if(node instanceof Yield) // expr
			return new LapYield(pyAST, (ChildField<? super LapYield>) parent, (Yield) node);
		if(node instanceof Compare) // expr
			return new LapCompare(pyAST, (ChildField<? super LapCompare>) parent, (Compare) node);
		if(node instanceof Call) // expr
			return new LapCall(pyAST, (ChildField<? super LapCall>) parent, (Call) node);
		if(node instanceof Repr) // expr
			return new LapRepr(pyAST, (ChildField<? super LapRepr>) parent, (Repr) node);
		if(node instanceof Num) // expr) // Value<Number>
			return new LapNum(pyAST, (ChildField<? super LapNum>) parent, (Num) node);
		if(node instanceof Str) // expr) // Value<String>
			return new LapStr(pyAST, (ChildField<? super LapStr>) parent, (Str) node);
		if(node instanceof Attribute) // expr
			return new LapAttribute(pyAST, (ChildField<? super LapAttribute>) parent, (Attribute) node);
		if(node instanceof Subscript) // expr
			return new LapSubscript(pyAST, (ChildField<? super LapSubscript>) parent, (Subscript) node);
		if(node instanceof Name) // expr
			return new LapName(pyAST, (ChildField<? super LapName>) parent, (Name) node);
		if(node instanceof List) // expr
			return new LapList(pyAST, (ChildField<? super LapList>) parent, (List) node);
		if(node instanceof Tuple) // expr
			return new LapTuple(pyAST, (ChildField<? super LapTuple>) parent, (Tuple) node);
		if(node instanceof Slice) // AST
			return new LapSlice(pyAST, (ChildField<? super LapSlice>) parent, (Slice) node);
		if(node instanceof ExtSlice) // AST
			return new LapExtSlice(pyAST, (ChildField<? super LapExtSlice>) parent, (ExtSlice) node);
		if(node instanceof Ellipsis) // AST
			return new LapEllipsis(pyAST, (ChildField<? super LapEllipsis>) parent, (Ellipsis) node);
		if(node instanceof Index) // AST
			return new LapIndex(pyAST, (ChildField<? super LapIndex>) parent, (Index) node);
		if(node instanceof comprehension) // AST
			return new LapComprehension(pyAST, (ChildField<? super LapComprehension>) parent, (comprehension) node);
		if(node instanceof ExceptHandler) // AST, PositionText
			return new LapExcepthandler(pyAST, (ChildField<? super LapExcepthandler>) parent, (ExceptHandler) node);
		if(node instanceof arguments) // AST
			return new LapArguments(pyAST, (ChildField<? super LapArguments>) parent, (arguments) node);
		if(node instanceof keyword) // AST
			return new LapKeyword(pyAST, (ChildField<? super LapKeyword>) parent, (keyword) node);
		if(node instanceof alias) // AST
			return new LapAlias(pyAST, (ChildField<? super LapAlias>) parent, (alias) node);
		
		throw new RuntimeException(node+"("+node.getClass()+") was not recognized as a valid node type...");
	}
	public static void makeHelpers(PyAST pyAST, ChildList<?> childList, java.util.List<? extends PythonTree> nodes)
	{
		for(PythonTree n : nodes)
		{
			makeHelper(pyAST, childList, n);
		}
	}
}
